﻿using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.Plugins;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Diagnostics;
using System.Linq;

namespace GatherHelper
{
    public class GatherHelperPlugin : HBPlugin
    {

        #region Globals

        public override string Name { get { return "GatherHelper"; } }
        public override string Author { get { return "toNyx"; } }
        public override Version Version { get { return new Version(0, 0, 0, 1); } }

        public override string ButtonText { get { return "Settings"; } }
        public override bool WantButton { get { return true; } }

        public override void OnButtonPress()
        {
            new SettingsForm().ShowDialog();
        }

        #endregion

        public Stopwatch SWaitTimer = new Stopwatch();
        public int StuckCount;
        public static string myJobs = "Herb"; // Change to "Herb", "Mine" or "Herb,Mine" in order to check objects
        public static WoWGameObject[] gatherNodes = null;

        public static void pLog(string msg)
        {
            Logging.Write("[GatherHelper] " + msg);
        }

        public override void Initialize()
        {
            Lua.Events.AttachEvent("LOOT_CLOSED", (sender, args) => Helpers.ResetTimer(SWaitTimer));
            //BotEvents.Player.OnPlayerDied += onDeath;

            Helpers.CreateFile();
            Helpers.WriteHotspotToFile();

            pLog(string.Format("Loaded Version : {0}",Version));
        }

        public override void Dispose()
        {
            Lua.Events.DetachEvent("LOOT_CLOSED", (sender, args) => Helpers.ResetTimer(SWaitTimer));
            BotEvents.Player.OnPlayerDied -= onDeath;
        }

        public override void Pulse()
        {

            /*
             * -----------------------------------
             * Nodes Retriever
             * -----------------------------------
             */

            switch (myJobs)
            {
                case "Mine":
                    gatherNodes = ObjectManager.GetObjectsOfType<WoWGameObject>().Where(o => o.IsMineral).ToArray(); // Mining Only
                    break;
                case "Herb":
                    gatherNodes = ObjectManager.GetObjectsOfType<WoWGameObject>().Where(o => o.IsHerb).ToArray(); // Herb Only 
                    break;
                case "Mine,Herb":
                    gatherNodes = ObjectManager.GetObjectsOfType<WoWGameObject>().Where(o => o.IsHerb || o.IsMineral).ToArray(); // Both
                    break;

            }

            /*
             * -----------------------------------
             * Dangerous Nodes remover
             * -----------------------------------
             */

            if (GatherHelperSettings.Instance.EnableBlackListingNodes)
            {
                gatherNodes.ForEach(
                    delegate(WoWObject node)
                        {
                            var nearbyHostileUnitsCount =  ObjectManager.GetObjectsOfTypeFast<WoWUnit>().FindAll(u =>
                                                                        u.IsHostile &&
                                                                        (u.Location.Distance(node.Location) <= GatherHelperSettings.Instance.DistanceOfUnitFromNodeMin || u.Location.Distance2D(node.Location) <= GatherHelperSettings.Instance.DistanceOfUnitFromNodeMin)
                                                           ).Count;

                            if (nearbyHostileUnitsCount >= GatherHelperSettings.Instance.NumberOfEnemiesAroundNodeMin && !Blacklist.Contains(node.Guid, BlacklistFlags.Node))
                            {
                                Blacklist.Add(node.Guid, BlacklistFlags.Node, TimeSpan.FromMinutes(1), "Too much nearby units who will slow us...");
                                if (GatherHelperSettings.Instance.LogBlacklistedNodes)
                                    pLog(string.Format("Blacklisting node at location [{0}] because there is {1} hostile units around...", node.Location, nearbyHostileUnitsCount));
                            }
                        });
            }


            /*
             * -----------------------------------
             * Stuck Handler
             * -----------------------------------
             */

            Helpers.StartTimer(SWaitTimer);

            if (SWaitTimer.Elapsed.TotalSeconds >= GatherHelperSettings.Instance.StuckTimerMax)
            {
				Helpers.ResetTimer(SWaitTimer);
				
				if (Helpers.IsStuck())
                {
                    StuckCount++;

                    pLog(string.Format("Stuck for {0} seconds (Stuck #{1})", GatherHelperSettings.Instance.StuckTimerMax,StuckCount));

                    if(ObjectManager.GetObjectsOfTypeFast<WoWUnit>().Any(u => u.Entry == 209311)) // Blacklisting the closest mining node.
                        Blacklist.Add(ObjectManager.GetObjectsOfTypeFast<WoWUnit>().Where(u => u.Entry == 209311).OrderBy(u => u.Distance).First().Guid, BlacklistFlags.Interact, new TimeSpan(0, 0, 3, 0), "We're having pain reaching the node, blacklist and force going for another.");

                    //Try to stop moving to trigger the Mount() method
                    WoWMovement.MoveStop();
                }
				
				// Use HearthStone attempt
                if ((GatherHelperSettings.Instance.UseHearthstoneWhenStuck && StuckCount >= GatherHelperSettings.Instance.HearthstoneStuckCount) || Helpers.IsStuckInCombatWithoutEnemies())
                    ObjectManager.GetObjectsOfTypeFast<WoWItem>().Where(item => !StyxWoW.Me.IsCasting && !StyxWoW.Me.IsChanneling).First(item => item.Entry == 6948 && item.CooldownTimeLeft == TimeSpan.Zero).Use();
            
                // Kill HB, seems like the stuck is strong in this one.
                if (GatherHelperSettings.Instance.KillHBWhenStuck && StuckCount >= GatherHelperSettings.Instance.KillHBStuckCount)
                    Environment.Exit(0); // Makes HB Exit itself
					
				// Reset StunCounter
				if (StuckCount >= GatherHelperSettings.Instance.HearthstoneStuckCount || StuckCount >= GatherHelperSettings.Instance.KillHBStuckCount)
					StuckCount = 0;

                Helpers.WriteHotspotToFile();
            }

            /*
             * -----------------------------------
             * Mount Helper
             * -----------------------------------
             */

            gatherNodes.Where(node => Helpers.IsDistanceGood(node) && Helpers.checkZ(node) && Helpers.Me.IsFlying).ForEach(
                delegate(WoWObject node)
                {
                    if (GatherHelperSettings.Instance.HelperDebug) pLog(string.Format("Reached node at [{0}]", node.Location));
					
					if (Helpers.IsBotGBorPB(TreeRoot.Current.Name))
					{
						if (Helpers.IsDruid() && Helpers.ShapeShiftCheck(Helpers.shapeshift))
						{
							if (GatherHelperSettings.Instance.HelperDebug) pLog("We are a druid, let's cancel the flying form to reach the node properly");
							Lua.DoString("RunMacroText('/cancelform')");
						}

						if (!Helpers.IsDruid() && Helpers.Me.Mounted)
						{
							if (GatherHelperSettings.Instance.HelperDebug) pLog("We are not a druid, let's dismount to reach the node properly");
							Lua.DoString("Dismount()"); 
						}
					}

                    StyxWoW.Sleep(new TimeSpan(0, 0, 0, 0, (50 * GatherHelperSettings.Instance.DistanceToDismount)));
                });
        }

        public void onDeath()
        {
            pLog(string.Format("We died, it'll take {0} seconds to reach it...", FlightPaths.GetRunPathTime(new[] { StyxWoW.Me.Location, StyxWoW.Me.CorpsePoint }, StyxWoW.Me.MovementInfo.CurrentSpeed).TotalSeconds));
        }
    }
}
